package com.zhuhjay.common.core.aspect;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.zhuhjay.common.base.annotation.ApiLimiter;
import com.zhuhjay.common.base.model.domain.LimiterDetail;
import com.zhuhjay.common.core.helper.ApiLimiterHelper;
import com.zhuhjay.common.security.context.LoginUserContext;
import com.zhuhjay.common.web.util.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import static com.zhuhjay.common.base.enums.LimiterEnums.IP;

/**
 * @author ZhuHJay
 * @date 2023/2/25 17:59
 */
@Slf4j
@Order(1)
@Aspect
@Component
public class ApiLimiterAspect {

    @Resource
    private ApiLimiterHelper apiLimiterHelper;

    /**
     * 使得切点为：Controller 接口且为 public 声明的(其他不希望被拦截的请使用别的修饰符)
     */
    @Before("execution(public * com.zhuhjay..controller.*..*(..))")
    public void before(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        ApiLimiter limiter = ((MethodSignature) signature).getMethod().getAnnotation(ApiLimiter.class);
        // 获取客户端访问ip、方法名、类名
        String ip = ServletUtil.getClientIP(ServletUtils.currentRequest());
        String methodName = signature.getName();
        String className = signature.getDeclaringType().getSimpleName();
        // 偷偷记录个日志吧
        HttpServletRequest request = ServletUtils.currentRequest();
        log.info("uri:[{}], method:[{}], ip:[{}]", request.getRequestURI(), request.getMethod(), ip);
        // 拼接key
        String suf = className + '.' + methodName;
        // 构建限流详细信息
        LimiterDetail limiterDetail = LimiterDetail.of(ip, limiter);
        // 判断是否为IP限流
        if (limiterDetail.getStrategy() != IP) {
            limiterDetail.setTarget(LoginUserContext.getUsername());
        }
        apiLimiterHelper.limiter(suf, limiterDetail,
                StrUtil.format("{} 访问过于频繁", request.getRequestURI()));
    }

}
